/*
 *  Copyright 2013 National Institute of Advanced Industrial Science and Technology
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.sss.mapreduce.example;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.sss.client.DataGetter;
import org.sss.client.SssClient;
import org.sss.mapreduce.GroupID;
import org.sss.mapreduce.Tuple;
import org.sss.mapreduce.datatype.PackableInt;
import org.sss.mapreduce.datatype.PackableString;

public class ShowUrlRankingApp {
  private final SssClient client;
  private boolean preserveFlag = false;
  private boolean reverseFlag = false;
  private GroupID gid;
  private ShowUrlRankingApp(String[] args) throws Exception {
    this.client = new SssClient(args);
    parseArgs(client.getArgs());
  }
  private void usage(final Options options) {
    HelpFormatter formatter = new HelpFormatter();
    formatter.printHelp("ShowUrlRankingApp [options] gid", options);
    System.exit(-1);
  }
  private void parseArgs(String[] args) {
    Options options = new Options();
    options.addOption("p", false, "preserve data");
    options.addOption("r", false, "reverse order");
    CommandLineParser parser = new BasicParser();
    CommandLine commandLine = null;
    try {
      commandLine = parser.parse(options, args);
      if (commandLine.hasOption("p")) { preserveFlag = true; }
      if (commandLine.hasOption("r")) { reverseFlag = true; }
      String[] gidList = commandLine.getArgs();
      if (gidList.length != 1) {
        System.err.println(gidList.length  < 1 ?
                           "no GroupID specified" :
                           "too many GroupIDs specified");
        usage(options);
      }
      gid = GroupID.createFromString(gidList[0]);
      if (preserveFlag) { gid = gid.getNonVolatileCopy(); }
    }
    catch (ParseException e) {
      usage(options);
    }
  }
  private <T> Iterator<T> sortedIterator(Iterator<T> it, Comparator<T> comparator) {
    List<T> list = new ArrayList<T>();
    while (it.hasNext()) {
      list.add(it.next());
    }
    Collections.sort(list, comparator);
    return list.iterator();
  }
  private Comparator<Tuple<PackableString, PackableInt>> keyValueComparator() {
    return new Comparator<Tuple<PackableString, PackableInt>>() {
      @Override
      public int compare(Tuple<PackableString, PackableInt> o1,
                         Tuple<PackableString, PackableInt> o2) {
        int count1 = o1.getValue().get();
        int count2 = o2.getValue().get();
        int valCmp = (count1 == count2) ? 0 : ((count1 < count2) ? -1 : 1);
        if (valCmp == 0) {
          return o1.getKey().get().compareTo(o2.getKey().get());
        }
        else {
          return valCmp;
        }
      }
      @Override
      public boolean equals(Object o) {
        return (this == o);
      }
    };
  }
  private void start() throws Exception {
    DataGetter<PackableString, PackableInt> dg =
      DataGetter.create(client, PackableString.class, PackableInt.class, gid);
    Iterator<Tuple<PackableString, PackableInt>> it =
      sortedIterator(dg.iterator(),
                     reverseFlag ?
                     keyValueComparator() :
                     Collections.reverseOrder(keyValueComparator()));
    Tuple<PackableString, PackableInt> kv;
    while (it.hasNext()) {
      kv = it.next();
      System.out.println(kv.getValue() + " " + kv.getKey());
    }
  }
  public static void main(String[] args) throws Exception {
    ShowUrlRankingApp app = new ShowUrlRankingApp(args);
    app.start();
    System.exit(0);
  }
}